package resources;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import java.io.IOException;
import tools.Bounds;

/** Sprites. */
public enum Sprite {
    /** Terrain. */
    LAND_FRONT("land/land-front.png", 5),
    LAND_SIDE("land/land-side.png", 4),
    LAND_TOP("land/land-top.png", 2),

    /** Merlin. */
    MAGE_STAND_DOWN("mage/mage-stand-down.png", 1),

    /** Fireballs. */
    FIREBALL_LEFT("fireball/fireball-left.png", 2),
    FIREBALL_RIGHT("fireball/fireball-right.png", 2),
    FIREBALL_UP("fireball/fireball-up.png", 2),
    FIREBALL_DOWN("fireball/fireball-down.png", 2),
    FIREBALL_UP_LEFT("fireball/fireball-up-left.png", 2),
    FIREBALL_UP_RIGHT("fireball/fireball-up-right.png", 2),
    FIREBALL_DOWN_LEFT("fireball/fireball-down-left.png", 2),
    FIREBALL_DOWN_RIGHT("fireball/fireball-down-right.png", 2),

    /** Monsters. */
    EYEBALL_LEFT("monsters/eyeball-left.png", 4),
    EYEBALL_RIGHT("monsters/eyeball-right.png", 4),
    EYEBALL_UP("monsters/eyeball-up.png", 4),
    EYEBALL_DOWN("monsters/eyeball-down.png", 4),

    /** Treasures. */
    TREASURE_DIAMOND("treasure/diamond.png", 1),
    TREASURE_RUBY("treasure/ruby.png", 1),
    TREASURE_EMERALD("treasure/emerald.png", 1),
    TREASURE_SAPPHIRE("treasure/sapphire.png", 1),

    /** Levels. */
    LEVEL_TEST("levels/test02.png", 1),

    /** Buttons. */
    NEW_GAME_BUTTON("buttons/new-game-button.png", 3),
    LOAD_GAME_BUTTON("buttons/load-game-button.png", 3),
    HOW_TO_PLAY_BUTTON("buttons/how-to-play-button.png", 3),
    MAIN_MENU_BUTTON("buttons/main-menu-button.png", 3);

    /** */
    private final String filename;
    /** */
    private final int frameCount;
    /** */
    private BufferedImage image;
    /** */
    private int frameWidth;
    /** */
    private int frameHeight;

    /**
     * @param newFilename - the filename.
     * @param newFrameCount - the number of frames.
     */
    private Sprite(final String newFilename, final int newFrameCount) {
        filename = newFilename;
        frameCount = newFrameCount;
    }

    /** @return the image associated with this sprite. */
    public BufferedImage getImage() {
        return image;
    }

    /** @return the filename. */
    public String getFilename() {
        return filename;
    }

    /** @return the number of frames in this sprite. */
    public int getFrameCount() {
        return frameCount;
    }

    /** @return the width of a frame in pixels. */
    public int getFrameWidth() {
        return frameWidth;
    }

    /** @return the height of a frame in pixels. */
    public int getFrameHeight() {
        return frameHeight;
    }

    /** Loads all the sprites in this enumeration. */
    public static void loadAll() {
        for (Sprite s : values()) {
            try {
                URL url = Sprite.class.getResource("/sprites/" + s.filename);
                System.out.println("Loading sprite: " + url);
                s.image = ImageIO.read(url);
            } catch (IOException e) {
                e.printStackTrace();
            }
            s.frameWidth = s.image.getWidth(null) / s.frameCount;
            s.frameHeight = s.image.getHeight(null);
        }
    }

    /**
     * Draws the sprite.
     * 
     * @param g a graphics object to draw the sprite to
     * @param frameIndex the frame to draw
     * @param x where to draw the sprite
     * @param y where to draw the sprite
     */
    public void draw(final Graphics g, final int frameIndex, final double x,
            final double y) {
        int x1 = (int) Math.round(x);
        int y1 = (int) Math.round(y);
        g.drawImage(image, x1, y1, x1 + frameWidth, y1 + frameHeight,
                frameWidth * frameIndex, 0, frameWidth * (frameIndex + 1),
                frameHeight, null);
    }

    /**
     * Draws the sprite anchored to the bottom centre of the given
     * bounding box.
     * 
     * @param g a graphics object to draw the sprite to
     * @param frameIndex the frame to draw
     * @param bounds where to draw the sprite
     */
    public void drawAnchored(final Graphics g, final int frameIndex,
            final Bounds bounds) {
        int x1 = (int) Math.round(bounds.getCenterX() - frameWidth / 2);
        int y1 = (int) Math.round(bounds.getMaxY() - frameHeight);

        g.drawImage(image, x1, y1, x1 + frameWidth, y1 + frameHeight,
                frameWidth * frameIndex, 0, frameWidth * (frameIndex + 1),
                frameHeight, null);

        // ALTERNATIVE - Much the same speed as far as I can tell
        // Shape oldClip = g.getClip();
        // g.setClip(x1, y1, frameWidth, frameHeight);
        // g.drawImage(image, x1 - frameWidth * frameIndex, y1, null);
        // g.setClip(oldClip);
    }

    /**
     * Draws the sprite anchored to the bottom centre of the given
     * bounding box. Also the sprite is scaled by the given factor.
     * 
     * @param g a graphics object to draw the sprite to
     * @param frameIndex the frame to draw
     * @param bounds where to draw the sprite
     * @param factor what to multiply the dimensions by
     */
    public void drawAnchoredScaled(final Graphics g, final int frameIndex,
            final Bounds bounds, final double factor) {
        int frameWidthScaled = (int) (frameWidth * factor);
        int frameHeightScaled = (int) (frameHeight * factor);
        int x1 = (int) Math.round(bounds.getCenterX() - frameWidthScaled / 2);
        int y1 = (int) Math.round(bounds.getMaxY()
                - (frameHeight + frameHeightScaled) / 2);
        g.drawImage(image, x1, y1, x1 + frameWidthScaled, y1
                + frameHeightScaled, frameWidth * frameIndex, 0, frameWidth
                * (frameIndex + 1), frameHeight, null);
    }
}
